From 8d701af28f2e5777a5cee19346a60859841459c6 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Fri, 12 Sep 2008 11:43:47 +0100 Subject: [PATCH] Check the existence of serial port before using Signed-off-by: Huacai Chen Signed-off-by: Keir Fraser --- xen/common/gdbstub.c | 15 ++++++++++++--- xen/drivers/char/console.c | 14 +++++++++++--- xen/drivers/char/ns16550.c | 34 ++++++++++++++++++++++++++++++++++ xen/drivers/char/serial.c | 10 ++++------ 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/xen/common/gdbstub.c b/xen/common/gdbstub.c index 7b8d231903..e578756a74 100644 --- a/xen/common/gdbstub.c +++ b/xen/common/gdbstub.c @@ -65,7 +65,7 @@ static atomic_t gdb_smp_paused_count; static void gdb_smp_pause(void); static void gdb_smp_resume(void); -static char opt_gdb[30] = "none"; +static char opt_gdb[30]; string_param("gdb", opt_gdb); static void gdbstub_console_puts(const char *str); @@ -625,10 +625,19 @@ __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie) void __init initialise_gdb(void) { + if ( *opt_gdb == '\0' ) + return; + gdb_ctx->serhnd = serial_parse_handle(opt_gdb); - if ( gdb_ctx->serhnd != -1 ) - printk("GDB stub initialised.\n"); + if ( gdb_ctx->serhnd == -1 ) + { + printk("Bad gdb= option '%s'\n", opt_gdb); + return; + } + serial_start_sync(gdb_ctx->serhnd); + + printk("GDB stub initialised.\n"); } static void gdb_pause_this_cpu(void *unused) diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index c326a6fd20..203f8459fc 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -543,10 +543,18 @@ void __init init_console(void) { if ( *p == ',' ) p++; - if ( strncmp(p, "com", 3) == 0 ) - sercon_handle = serial_parse_handle(p); - else if ( strncmp(p, "vga", 3) == 0 ) + if ( !strncmp(p, "vga", 3) ) vga_init(); + else if ( strncmp(p, "com", 3) || + (sercon_handle = serial_parse_handle(p)) == -1 ) + { + char *q = strchr(p, ','); + if ( q != NULL ) + *q = '\0'; + printk("Bad console= option '%s'\n", p); + if ( q != NULL ) + *q = ','; + } } serial_set_rx_handler(sercon_handle, serial_rx); diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c index 66a8058cdb..a66a4999f2 100644 --- a/xen/drivers/char/ns16550.c +++ b/xen/drivers/char/ns16550.c @@ -82,6 +82,7 @@ static struct ns16550 { #define MCR_DTR 0x01 /* Data Terminal Ready */ #define MCR_RTS 0x02 /* Request to Send */ #define MCR_OUT2 0x08 /* OUT2: interrupt mask */ +#define MCR_LOOP 0x10 /* Enable loopback test mode */ /* Line Status Register */ #define LSR_DR 0x01 /* Data ready */ @@ -295,6 +296,37 @@ static int __init parse_parity_char(int c) return 0; } +static int check_existence(struct ns16550 *uart) +{ + unsigned char status, scratch, scratch2, scratch3; + + /* + * Do a simple existence test first; if we fail this, + * there's no point trying anything else. + */ + scratch = ns_read_reg(uart, IER); + ns_write_reg(uart, IER, 0); + + /* + * Mask out IER[7:4] bits for test as some UARTs (e.g. TL + * 16C754B) allow only to modify them if an EFR bit is set. + */ + scratch2 = ns_read_reg(uart, IER) & 0x0f; + ns_write_reg(uart, IER, 0x0F); + scratch3 = ns_read_reg(uart, IER) & 0x0f; + ns_write_reg(uart, IER, scratch); + if ( (scratch2 != 0) || (scratch3 != 0x0F) ) + return 0; + + /* + * Check to see if a UART is really there. + * Use loopback test mode. + */ + ns_write_reg(uart, MCR, MCR_LOOP | 0x0A); + status = ns_read_reg(uart, MSR) & 0xF0; + return (status == 0x90); +} + #define PARSE_ERR(_f, _a...) \ do { \ printk( "ERROR: " _f "\n" , ## _a ); \ @@ -357,6 +389,8 @@ static void __init ns16550_parse_port_config( PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits); if ( uart->io_base == 0 ) PARSE_ERR("I/O base address must be specified."); + if ( !check_existence(uart) ) + PARSE_ERR("16550-compatible serial UART not present"); /* Register with generic serial driver. */ serial_register_uart(uart - ns16550_com, &ns16550_driver, uart); diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index 2d0dcd5351..9628b2c96b 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -258,11 +258,7 @@ int serial_parse_handle(char *conf) { int handle; - /* Silently fail if user has explicitly requested no serial I/O. */ - if ( strcmp(conf, "none") == 0 ) - return -1; - - if ( strncmp(conf, "com", 3) != 0 ) + if ( strncmp(conf, "com", 3) ) goto fail; switch ( conf[3] ) @@ -277,6 +273,9 @@ int serial_parse_handle(char *conf) goto fail; } + if ( !com[handle].driver ) + goto fail; + if ( conf[4] == 'H' ) handle |= SERHND_HI; else if ( conf[4] == 'L' ) @@ -287,7 +286,6 @@ int serial_parse_handle(char *conf) return handle; fail: - printk("ERROR: bad serial-interface specification '%s'\n", conf); return -1; } -- 2.30.2